/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.meta.service.excel.impl;


import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.StyleSet;
import cn.hutool.poi.excel.cell.CellUtil;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.base.Strings;
import com.je.common.base.DynaBean;
import com.je.common.base.exception.PlatformException;
import com.je.common.base.exception.PlatformExceptionEnum;
import com.je.common.base.util.ArrayUtils;
import com.je.common.base.util.MathExtend;
import com.je.common.base.util.StringUtil;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.meta.rpc.excel.AbstractExcelRpcExportService;
import net.sf.json.JSONArray;
import org.apache.poi.ss.usermodel.*;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.*;

/**
 * 打印样式导出
 */
@Service("excelRpcReportExportService")
public class ExcelRpcReportExportServiceImpl extends AbstractExcelRpcExportService {


    @Override
    public InputStream export(JSONObject params, HttpServletRequest request) {
        String queryType = params.getString("queryType");
        String styleType = params.getString("styleType");
        String funcId = params.getString("funcId");
        String sheetId = params.getString("sheetId");
        String title = params.getString("title");
        String fieldPlan = params.getString("fieldPlan");
        String whereSql = params.getString("whereSql");
        String tableCode = params.getString("tableCode");

        //查询数据
        //List<DynaBean> datas = expData(params, request);
        List<DynaBean> datas = metaService.select(tableCode,ConditionsWrapper.builder().apply(whereSql));
        if (datas.size() > 1048570) {
            throw new PlatformException("数据条数大于1048570,无法导出!", PlatformExceptionEnum.JE_CORE_EXCEL_EXP_ERROR);
        }
        //获取功能字段列配置
        List<DynaBean> columns = excelRpcService.getReportColumns(funcId,fieldPlan);

        //封装字典数据
        Map<String, Map<String, String>> ddInfos = excelRpcService.buildDicDatas(columns);

        //获取ExcelWriter操作对象
        ExcelWriter writer = ExcelUtil.getWriter(true);

        //样式
        StyleSet style = writer.getStyleSet();

        //大标题样式
        CellStyle titleCellStyle = writer.getWorkbook().createCellStyle();
        Font tFont = writer.createFont();
        tFont.setFontName("宋体");
        //字号
        tFont.setFontHeightInPoints((short) 18);
        titleCellStyle.setFont(tFont);
        titleCellStyle.setAlignment(HorizontalAlignment.CENTER);
        titleCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
//        titleCellStyle.setFillForegroundColor(HSSFColor.LIGHT_GREEN.index);
        //设置列名样式
        CellStyle headCellStyle = style.getHeadCellStyle();
        Font headFont = writer.createFont();
        headFont.setFontName("宋体");
        //字号
        headFont.setFontHeightInPoints((short) 12);
        headCellStyle.setFont(headFont);
        headCellStyle.setWrapText(true);
        headCellStyle.setAlignment(HorizontalAlignment.CENTER);
        headCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        headCellStyle.setBorderTop(BorderStyle.THIN);
        headCellStyle.setBorderLeft(BorderStyle.THIN);
        headCellStyle.setBorderRight(BorderStyle.THIN);
        headCellStyle.setBorderBottom(BorderStyle.THIN);

        //设置数据样式
        CellStyle cellStyle = style.getCellStyle();
        Font font = writer.createFont();
        font.setFontName("宋体");
        //字号
        font.setFontHeightInPoints((short) 10);
        cellStyle.setFont(font);
        cellStyle.setBorderTop(BorderStyle.THIN);
        cellStyle.setBorderLeft(BorderStyle.THIN);
        cellStyle.setBorderRight(BorderStyle.THIN);
        cellStyle.setBorderBottom(BorderStyle.THIN);
        DataFormat format = writer.getWorkbook().createDataFormat();
        //单元格默认设置文本
        cellStyle.setDataFormat(format.getFormat("@"));


        //处理多表头
        Boolean haveMore = false;
        List<DynaBean> dataColumns = new ArrayList<DynaBean>();
        for (DynaBean moreColumn : columns) {
            if (!"morecolumn".equals(moreColumn.getStr("RESOURCECOLUMN_XTYPE")) && !StringUtil.isNotEmpty(moreColumn.getStr("RESOURCECOLUMN_MORECOLUMNNAME"))) {
                dataColumns.add(moreColumn);
                continue;
            }
            haveMore = true;
            String code = moreColumn.getStr("RESOURCECOLUMN_CODE");
            List<DynaBean> childrens = new ArrayList<DynaBean>();
            for (DynaBean dataColumn : columns) {
                if (code.equals(dataColumn.getStr("RESOURCECOLUMN_MORECOLUMNNAME"))) {
                    childrens.add(dataColumn);
                    dataColumns.add(dataColumn);
                }
            }
            moreColumn.set("children", childrens);
        }

        //大标题
        //EDIT BY ZHANGYD FOR EXCEL导出单列报错 20200918
        if (dataColumns.size() == 1 && StringUtil.isNotEmpty(title)) {
            Cell cell = writer.getOrCreateCell(0, 0);
            CellUtil.setCellValue(cell, title, writer.getStyleSet(), true);
        } else {
            writer.merge(0, 0, 0, dataColumns.size() - 1, title, true);
        }
        Cell titleCell = writer.getOrCreateCell(0, 0);
        titleCell.setCellStyle(titleCellStyle);

        writer.setRowHeight(0, 30);

        Integer startRow = 2;
        int valueLength = 0;
        int rowCount =0;
        int rowLength=0;
        //列名标题
        if (!haveMore) {
            for (Integer i = 0; i < dataColumns.size(); i++) {
                DynaBean column = dataColumns.get(i);
                //设置宽度
                Integer width = columnWidth(column);
                writer.setColumnWidth(i, width);

                writer.writeCellValue(i, 1, column.getStr("RESOURCECOLUMN_NAME"));

                //设置列名标题样式
                Cell c = writer.getOrCreateCell(i, 1);
                c.setCellStyle(headCellStyle);
            }
            //设置标题高度
            writer.setRowHeight(1, 18);
        } else {
            startRow = 3;
            //设置标题
            Integer nowColumnIndex = 0;
            Set<String> columnCodes = new HashSet<>();
            for (Integer i = 0; i < columns.size(); i++) {
                DynaBean moreColumn = columns.get(i);
                String columnCode = moreColumn.getStr("RESOURCECOLUMN_CODE");
                if (columnCodes.contains(columnCode)) {
                    continue;
                }
                if ("morecolumn".equals(moreColumn.getStr("RESOURCECOLUMN_XTYPE"))) {
                    List<DynaBean> childrens = (List<DynaBean>) moreColumn.get("children");
                    if (childrens.size() <= 0) {
                        continue;
                    }
                    writer.merge(1, 1, nowColumnIndex, nowColumnIndex + childrens.size() - 1, moreColumn.getStr("RESOURCECOLUMN_NAME"), true);

                    //处理多表头下的列
                    for (Integer j = 0; j < childrens.size(); j++) {
                        DynaBean column = childrens.get(j);
                        //设置宽度
                        Integer width = columnWidth(column);
                        writer.setColumnWidth(nowColumnIndex + j, width);
                        writer.writeCellValue(nowColumnIndex + j, 2, column.getStr("RESOURCECOLUMN_NAME"));

                        //设置列名标题样式
                        Cell c = writer.getOrCreateCell(nowColumnIndex + j, 2);
                        c.setCellStyle(headCellStyle);

                        columnCodes.add(column.getStr("RESOURCECOLUMN_CODE"));
                    }
                    nowColumnIndex += childrens.size();
                } else {
                    if (StringUtil.isNotEmpty(moreColumn.getStr("RESOURCECOLUMN_MORECOLUMNNAME"))) {
                        continue;
                    }

                    //设置宽度
                    Integer moreWidth = columnWidth(moreColumn);
                    writer.setColumnWidth(nowColumnIndex, moreWidth);
                    writer.merge(1, 2, nowColumnIndex, nowColumnIndex, moreColumn.getStr("RESOURCECOLUMN_NAME"), true);
                    nowColumnIndex++;
                }
                columnCodes.add(columnCode);
            }

            //标题高度
            writer.setRowHeight(1, 18);
            writer.setRowHeight(2, 18);
        }

        //填充数据
        for (Integer i = 0; i < datas.size(); i++) {
            DynaBean dynaBean = datas.get(i);
            for (Integer j = 0; j < dataColumns.size(); j++) {
                DynaBean column = dataColumns.get(j);
                if ("rownumberer".equals(column.getStr("RESOURCECOLUMN_XTYPE"))) {
                    writer.writeCellValue(j, startRow + i, i + 1);
                    continue;
                }
                String xtype = column.getStr("RESOURCEFIELD_XTYPE");
                if (ArrayUtils.contains(new String[]{"rgroup", "cgroup", "cbbfield"}, xtype)) {
                    writer.writeCellValue(j, startRow + i, getDdValue(ddInfos, column, dynaBean.getStr(column.getStr("RESOURCECOLUMN_CODE", ""))));
                } else {
                    if (ArrayUtils.contains(new String[]{"numberfield"}, xtype)) {
                        String config = column.getStr("RESOURCEFIELD_CONFIGINFO");
                        if (!Strings.isNullOrEmpty(config) && config.equals("0")) {
                            String value = String.valueOf(dynaBean.getDouble(column.getStr("RESOURCECOLUMN_CODE"), 0));
                            writer.writeCellValue(j, startRow + i, value.substring(0, value.indexOf(".")));
                        } else {
                            writer.writeCellValue(j, startRow + i, dynaBean.getDouble(column.getStr("RESOURCECOLUMN_CODE"), 0));
                        }
                    } else {
                        if (!Strings.isNullOrEmpty(dynaBean.getStr(column.getStr("RESOURCECOLUMN_CODE", "")))) {
                            String value = dynaBean.getStr(column.getStr("RESOURCECOLUMN_CODE", ""));
                            if (!Strings.isNullOrEmpty(column.getStr("RESOURCEFIELD_XTYPE")) && column.getStr("RESOURCEFIELD_XTYPE").equals("uxfilefield")) {
                                dynaBean.set(column.getStr("RESOURCECOLUMN_CODE"), value.split("\\*")[0]);
                            }
                            if (!Strings.isNullOrEmpty(column.getStr("RESOURCEFIELD_XTYPE")) && column.getStr("RESOURCEFIELD_XTYPE").equals("uxfilesfield")) {
                                StringBuffer newValue = new StringBuffer();
                                net.sf.json.JSONArray files = JSONArray.fromObject(value);
                                for (Object file : files) {
                                    net.sf.json.JSONObject js = (net.sf.json.JSONObject) file;
                                    newValue.append(js.getString("name") + "<br/>");
                                }
                                value = newValue.toString();
                                value = value.substring(0, value.length() - 5);
                                dynaBean.set(column.getStr("RESOURCECOLUMN_CODE"), value);
                            }
                            if (!Strings.isNullOrEmpty(column.getStr("RESOURCEFIELD_XTYPE")) && column.getStr("RESOURCEFIELD_XTYPE").equals("barfield")) {
                                dynaBean.set(column.getStr("RESOURCECOLUMN_CODE"), value+"%");
                            }
                            writer.writeCellValue(j, startRow + i, dynaBean.getStr(column.getStr("RESOURCECOLUMN_CODE", "")).replaceAll("<br/>", String.valueOf((char) 10)));
                            writer.getCellStyle().setWrapText(true);
                        } else {
                            writer.writeCellValue(j, startRow + i, "");
                            writer.getCellStyle().setWrapText(true);
                        }
                    }
                }
            }
        }
        //初始化输出流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        //将Excel内容写入输出流
        writer.flush(outputStream);
        //输出转输入
        ByteArrayInputStream inputStream = IoUtil.toStream(outputStream.toByteArray());
        //关闭ExcelWriter outputStream
        IoUtil.close(writer);
        IoUtil.close(outputStream);
        return inputStream;
    }

    private int columnWidth(DynaBean column) {
        Integer width = column.getInt("RESOURCECOLUMN_WIDTH", 80);
        //暂定比例  按照  1个字符是6像素计算
        Double w = MathExtend.divide(width / (double) 6, 1, 0);
        //将像素换算成excel宽度      此方法参数意思是：单位的1/256th字符宽度
        return Integer.parseInt(new java.text.DecimalFormat("0").format(w));
    }

    /**
     * 获取字典字段的code的name值
     *
     * @param ddInfos
     * @param column
     * @param codeValue
     * @return
     */
    private String getDdValue(Map<String, Map<String, String>> ddInfos, DynaBean column, String codeValue) {
        String xtype = column.getStr("RESOURCEFIELD_XTYPE");
        //多选框
        Map<String, String> ddItems = null;
        String configInfo = column.getStr("RESOURCEFIELD_CONFIGINFO");
        if (StringUtil.isNotEmpty(configInfo)) {
            String ddCode = configInfo.split(",")[0];
            ddItems = ddInfos.get(ddCode);
        }
        if (ddItems != null) {
            if ("cgroup".equals(xtype)) {
                if (StringUtil.isNotEmpty(codeValue)) {
                    String[] codeValues = codeValue.split(",");
                    for (Integer i = 0; i < codeValues.length; i++) {
                        if (StringUtil.isNotEmpty(codeValues[i]) && ddItems.get(codeValues[i]) != null) {
                            codeValues[i] = ddItems.get(codeValues[i]);
                        }
                    }
                    return StringUtil.buildSplitString(codeValues, ",");
                } else {
                    return codeValue;
                }
            } else {
                if (StringUtil.isNotEmpty(codeValue) && ddItems.get(codeValue) != null) {
                    return ddItems.get(codeValue);
                } else {
                    return codeValue;
                }
            }
        } else {
            return codeValue;
        }
    }

}
